package com.turing.model.caller.handler;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.turing.common.config.ServerConfig;
import com.turing.common.response.ResponseVO;
import com.turing.common.response.model.ResVO;
import com.turing.common.util.HttpUtils;
import com.turing.common.util.Tools;
import com.turing.model.caller.client.task.manager.DrawClient;
import com.turing.model.caller.service.DrawService;
import com.turing.model.caller.service.ModelService;
import com.turing.model.caller.vo.in.FileTaskVo;
import com.turing.model.caller.vo.out.ForecastVO;
import com.turing.model.caller.vo.out.ModelCallParamsVo;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
public class ForecastCallerHandler {

    @Autowired
    private ModelService modelService;

    @Autowired
    private ServerConfig serverConfig;

    @Autowired
    private DrawClient drawClient;

    @Autowired
    private DrawService drawService;

    private static final Logger logger = LoggerFactory.getLogger(ForecastCallerHandler.class);

    // reuse xxl-job handler by set different domain
    @XxlJob(value="callForecastJobHandler")
    @Transactional(propagation = Propagation.REQUIRED)
    public void callForecastModel() {

        String url = serverConfig.getUrl();
        // get job param
        String param = XxlJobHelper.getJobParam();
        String[] split = param.split("_");
        // 拉取预测任务时区别父任务不拉取
        ResponseVO<FileTaskVo> getResVo = drawService.getAndLockForecastTask(url, split[2]);
        if( getResVo.getCode().equals("200") ){

            FileTaskVo fileTaskVo = getResVo.getData();
            logger.info("****************拉取任务成功 taskSn:" + fileTaskVo.getTaskSn() + "fileName:"+ fileTaskVo.getFileName()
                    +"parentFileTaskSn:" + fileTaskVo.getParentTaskSn() + " ********************");
            if( !fileTaskVo.equals(new FileTaskVo()) ){

                String taskSn = fileTaskVo.getTaskSn();
                // call model

                if(modelService.statusOK(split[0], split[1])){
                    String httpUrl = "http://" +split[0] + "/api/model/predict";
                    // call model
                    String res = "";
                    try{
                        String params = JSON.toJSONString(ModelCallParamsVo.builder()
                                .task_id(taskSn)
                                .gpu_id(split[1])
                                .element_id(fileTaskVo.getTemplateId())
                                .file_name(fileTaskVo.getFileName())
                                .ocr_file_id(fileTaskVo.getOcrJsonUrl()).build());
                        logger.info("start calling forecast ,params is:"+params+"taskSn is:"+taskSn+",file name is:"+fileTaskVo.getFileName());
                        res = HttpUtils.doPost(httpUrl, params , 3000000);
                    }catch (Exception e){
                        logger.error("=====> /api/model/predict 调用异常"+e.getMessage());
                        e.printStackTrace();
                        drawClient.unLockForecastTask(fileTaskVo.getTaskSn());
                    }
                    logger.info("=================>api/model/predict res= "+res);
                    ResVO<JSONObject> resVO = JSONObject.parseObject(res, new TypeReference<ResVO<JSONObject>>(){});
                    //logger.info(resVO.toString());
                    // callback
                    if(resVO.getCode().equals("0")){
                        JSONObject data = resVO.getData();
                        if(data != null){
                            JSONObject elements = data.getJSONObject("_merge");
                            Map<String, List<ForecastVO>> transObj = new HashMap<>();
                            if(Tools.isNotEmpty(elements)){
                                elements.keySet().forEach(
                                        k->{
                                            JSONArray jsonArray = elements.getJSONArray(k);
                                            transObj.put(k,jsonArray.toJavaList(ForecastVO.class));
                                        }
                                );
                                logger.info("_merge:"+elements.size());
                            }

                            try{
                                ResponseVO<Object> objectResponseVO = drawClient.forecastResultCallback(transObj, taskSn, fileTaskVo.getParentTaskSn(), fileTaskVo.getTemplateId());
                                logger.info("==>回调结束：status is:" + objectResponseVO.getCode()+"taskSn is:"+taskSn+",file name is:"+fileTaskVo.getFileName());
                            }catch (Exception e2){
                                drawClient.unLockForecastTask(taskSn);
                                e2.printStackTrace();
                            }
                        }
                    }else{
                        logger.info("forecast response not okay,taskSn is:"+fileTaskVo.getTaskSn()+",file name is:"+fileTaskVo.getFileName(),"taskSn is:"+taskSn);
                        logger.info("res is:"+resVO.toString());
                        drawClient.unLockForecastTask(taskSn);
                    }
                }else{
                    logger.info("status not okay,taskSn is:"+taskSn);
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    logger.info("wake up from sleep 5s,taskSn is:"+taskSn);
                    drawClient.unLockForecastTask(taskSn);
                }
            }
        }
    }


}
